# -*- coding: utf-8 -*-
import sys

# Try to import 'btsocket' as 'socket' - ignore on versions < 1.9.x
try:
    sys.modules['socket'] = __import__('btsocket')
except ImportError:
    pass

# For v1.9.x - Import the 'btsocket' module as 'socket'
# For v1.4.x - Import 'socket' module
import btsocket
import re, time, os, urllib, sysinfo
import key_codes
import sys
import e32
from httplib import HTTP
import httplib
from e32 import *
from appuifw import *
import appuifw
from window import Application, Dialog, Splash
from about import About
from settings import Settings, sel_access_point
from wmutil import *
from wmglobals import VERSION, DEFDIR, AVATARSDIR
from persist import DB
from s60twitter import TwitterApi
from canvaslistbox import CanvasListBox
from urllibproxy import UrllibProxy
import positioning
import location
import globalui
from string import replace
from struct import unpack
from struct import pack
import audio
import sysinfo
import pyS60uiutil
import twitpic

__all__ = [ "Cagnutty" ]
__author__ = "Cagnulein (cagnulein@gmail.com)"
__version__ = VERSION
__copyright__ = "Copyright (c) 2010 - Cagnulein"
__license__ = "GPLv3"

class Notepad(Dialog):
    def __init__(self, cbk, txt=u"", twitter_username=u"",twitter_password=u"" , twu=[]):
        self.twu = twu
        self.twitter_username=twitter_username
        self.twitter_password=twitter_password
        self.twu.sort()
        menu = [(u"Send", self.close_app),
                (u"Discard", self.cancel_app)]
        if self.twu:
            menu += [(u"Add user", self.adduser)]
        menu += [(u"Add Image", self.addimage)]

        body=Text()
        try:
           if(txt!=""):
              body.add(txt)
        except Exception, e:
           note(u"Impossible to add test","error")
           note(u"%s" % e,"error")
           txt=u""
        Dialog.__init__(self, cbk, u"New update", body, menu)

    def addimage(self):
        d=pyS60uiutil.dirBrowser()
        f=d.select()
        try:
           if f!=None:
              twit=twitpic.TwitPicAPI(self.twitter_username,self.twitter_password)
              url=twit.upload(f[0]+u"\\"+f[1],f[1])
              self.body.add(url)           
        except Exception, e:
           note(u"Impossible to add an image","error")
           note(u"%s" % e,"error")

    def adduser(self):
        # this list may be large .... better to think about latter
        sel = multi_selection_list(self.twu, style='checkbox', search_field=1)
        if sel:
            usrs = "".join([ u"@" + self.twu[idx] + u" " for idx in sel ])
            self.body.add(usrs)

    def close_app(self):
        if not self.cancel:
            yn = popup_menu([u"Yes",u"No"],u"Send update?")
            if yn is None:
                return
            if yn == 1:
                self.cancel = True
            else:
                self.cancel = False

        Dialog.close_app(self)
        
class Iamdoing(Application):
    
    def __init__(self):
        menu = [ (u"Setting", self.settings),
                 (u"About", self.about),
                 (u"Close", self.close_app)]
        self.body = CanvasListBox([], [], self.check_update_value)
        Application.__init__(self,  u"I am doing ...", self.body, menu)
        self.dlg = None
        self.twitter_user = ""
        self.twitter_password = ""
        self.proxy = ""
        self.twitter_api = None
        self.page = 1
        self.gps_on = False
        self.headlines = []
        self.avatars = []
        self.twt_users = {}
        self.timeline = {}
        self.last_idx = 0
        self.update_msg = u""
        self.last_tweet = u""
        self.no_notification=False
        self.refresh_timer = e32.Ao_timer()
        self.gps_timer = e32.Ao_timer()                    
        self.socket=sel_access_point()        
        self.check_conn_params()

        self.bind(key_codes.EKeyRightArrow, self.inc_page)
        self.bind(key_codes.EKeyLeftArrow, self.dec_page)

        self.mcc=0
        while self.mcc==0:
           try:   
              self.mcc, self.mnc, self.lac, self.cellId = location.gsm_location()  
           except:
              print "gsm error"
              e32.ao_sleep(3)

    def run(self):
        # #############################
        #Splash screen steps
        
        #Get graphics path
        #Code from Forum Nokia's Wiki 
        try:
            raise Exception
        except Exception:
            frame = sys.exc_info()[2].tb_frame
            path = frame.f_code.co_filename
        path = path.replace(u"iamdoing.py", u"")

        #Checks the screen orientation (landscape or portrait)
        w, h = sysinfo.display_pixels()
        if w > h:
            self.splash_image = path + "graphics\\splash-landscape.png"
        else:
            self.splash_image = path + "graphics\\splash-protrait.png"
            
        #print self.splash_image
        #note(self.splash_image,"info")
        def cbk_splash():
            # NOP callback to splash class
            return True
        
        #splash screen code
        #self.main_timer = Ao_timer()
        #s = Splash(cbk_splash, self.splash_image, self.main_timer, 2)
        app.screen = 'normal'
        #End of splash screen steps
        # #############################

        if self.twitter_user!="":
           self.refresh_pages()
        Application.run(self)

    def check_conn_params(self):
        if DB["proxy_enabled"] == u"True":
            user = unicode_to_utf8( DB["proxy_user"] )
            addr = unicode_to_utf8( DB["proxy_addr"] )
            port = unicode_to_utf8( DB["proxy_port"] )
            user = unicode_to_utf8( DB["proxy_user"] )
            pwrd = unicode_to_utf8( DB["proxy_pass"] )
            
            if user:
                self.proxy = "http://%s:%s@%s:%s" % (user,pwrd,addr,port)
            else:
                self.proxy = "http://%s:%s" % (addr,port)
        else:
            self.proxy = ""
            
        self.twitter_user = DB["twitter_user"]             
        self.twitter_password = DB["twitter_pass"]
        self.twitter_api = TwitterApi(self.twitter_user,
                                      self.twitter_password,
                                      self.proxy)
        
        if (DB["gps_enabled"] == u"True"):
            self.gps_enabled=True
        else:
            self.gps_enabled=False 

        if(self.gps_enabled):
            if(self.gps_on==False):
               self.gps_init()
        else:
            self.gps_stop()

    def inc_page(self):
        if not self.ui_is_locked():
            self.page += 1
            self.refresh_timeline()

    def dec_page(self):
        if not self.ui_is_locked():
            self.page -= 1
            if self.page < 1:
                self.page = 1
            else:
                self.refresh_timeline()

    def check_update_value(self):
        if not self.ui_is_locked():
           self.update_value()
            
    def update_value(self):
        idx = self.body.current()
        self.last_idx = idx
        menu = [(u"Refresh", self.cbk_refresh_pages),
                (u"Send update", self.send_update)]
        if not self._is_mine(idx) and self.timeline.has_key(self.page):
            menu += [(u"Reply", self.reply)]
        if not self._is_mine(idx) and self.timeline.has_key(self.page):
            menu += [(u"Retweet", self.retweet)]            
        if self._has_link(idx):
            menu += [(u"Follow links", self.follow_links)]
        if self._is_mine(idx):
            menu += [(u"Delete",self.delete)]
            
        op = popup_menu(map( lambda x: x[0], menu ), u"Menu:")
        if op is not None:
            map(lambda x: x[1], menu)[op]()

    def _has_link(self,idx):
        idx = self.body.current()
        if self.timeline.has_key(self.page):
            msg = self.timeline[self.page][idx][u'text']
            http = re.compile(u"http://\S+", re.IGNORECASE)
            links = re.findall(http, msg)
            if links:
                return True
        return False
    
    def _is_mine(self,idx):
        idx = self.body.current()
        if self.timeline.has_key(self.page):
            if self.timeline[self.page][idx][u'user'][u'screen_name'] == self.twitter_user:
                return True
        return False

    def cbk_refresh_pages(self):
        self.no_notification=True
        self.refresh_pages()

    def refresh_pages(self):
        self.timeline = {}
        self.page = 1
        self.refresh_timeline()
        
    def refresh_timeline(self):        
        self.page = 1
        
        if not self.timeline.has_key(self.page):            
            self.lock_ui(u"Downloading page %d..." % self.page)
            try:
                self.timeline[self.page] = self.twitter_api.get_friends_timeline(self.page)
            except Exception, e:
                note(u"Impossible to download page %d..." % self.page,"error")
                note(u"%s" % e,"error")
                self.unlock_ui()
                self.refresh()
                self.socket.stop()
                return
            # get all avatars not yet in local cache
            urlprx = UrllibProxy(self.proxy)
            for u in self.timeline[self.page]:
                url = u[u'user'][u'profile_image_url']
                uid = str(u[u'user'][u'id'])
                img_type = url[url.rfind("."):]
                img_file = os.path.join(AVATARSDIR,uid+img_type).lower()
                if not os.path.exists(img_file):
                    self.set_title(u"Updating %s" % u[u'user'][u'screen_name'])
                    try:
                        urlprx.urlretrieve(url,img_file)
                    except Exception, e:
                        note(u"Avatar for %s failed" % u[u'user'][u'screen_name'],"error")
                        note(u"%s" % e,"error")
                if not self.twt_users.has_key(uid):
                    self.twt_users[uid] = u[u'user'][u'screen_name']
                    
            self.unlock_ui()
                
        self.headlines = []
        self.avatars = []
        try:
           for msg in self.timeline[self.page]:
               r1 = msg[u'user'][u'screen_name']
               if msg[u'in_reply_to_screen_name']:
                  r1 += u" to %s" % msg[u'in_reply_to_screen_name']
               #r1 += u" %s" % self.twitter_api.human_msg_age(msg[u'created_at'])
               r2 = msg[u'text']
               self.headlines.append(r1 + u" " + r2)
               url = msg[u'user'][u'profile_image_url']
               img = str(msg[u'user'][u'id'])+url[url.rfind("."):]
               self.avatars.append(os.path.join(AVATARSDIR,img.lower()))
        except Exception, e:
            note(u"Impossible to load avatar...","error")
            note(u"%s" % e,"error")
        self.last_idx = 0
        self.refresh()
        self.socket.stop()
        
        refresh_time=int(DB["refresh_time"])
        if(refresh_time>0):
           self.refresh_timer.cancel()
           self.refresh_timer.after(refresh_time*60, self.refresh_pages)
              
        try:      
            if self.last_tweet!=u"" and self.no_notification==False:               
                notification=u""   
                notification_to_say=u""
                idx=self.body.current()
                for msg in self.timeline[self.page]:
                    if msg[u'text']!=self.last_tweet and msg[u'user'][u'screen_name']!=self.twitter_user:
                        notification += msg[u'user'][u'screen_name'] + ": " + msg['text'] + ". "
                        #notification_to_say += u"New Tweet from " + msg[u'user'][u'screen_name'] + ": " + msg['text'] + ". "
                    else:
                        break
                  
                if notification!=u"":
                    #if sysinfo.active_profile() == u"general" or sysinfo.active_profile() == u"outdoor":
                    #    audio.say(notification_to_say)
                    globalui.global_msg_query(notification,u"New Tweet/s")
        except Exception, e:
            note(u"Notification error...","error")
            note(u"%s" % e,"error")
            
        self.no_notification=False    
            
        try:
            idx = self.body.current()
            self.last_tweet = self.timeline[self.page][idx][u'text']
        except Exception, e:
            print u"Impossible to retrieve the newest tweet..."
            
        #self.check_update_value()
        idx = self.body.current()
        self.last_idx = idx

    def _splitmsg(self,msg):
        msgs = []
        words = msg.split()
        frag = ""
        for w in words:
            if len(frag + w + "  ...")<140:
                if frag:
                    frag += " " + w
                else:
                    frag += w
            else:
                if len(frag) < 140 and len(frag) > 0: 
                    frag += " ..."
                    msgs.insert(0,frag)
                    frag = "... " + w
                else: # large single word ... :-(
                    for i in range(0,len(frag),139):
                        msgs.insert(0,frag[i:i+139])
                    frag = w
        msgs.insert(0,frag)
        return msgs

    def send_update_cbk(self):
        if not self.dlg.cancel:
            msg = self.dlg.body.get()
            msg = unicode_to_utf8(msg)
            # first, convert links, if any
            http = re.compile("http://\S+", re.IGNORECASE)
            links = re.findall(http, msg)
            
            self.lock_ui()
            if links:
                for t in links:
                    self.set_title(u"URL: %s" % t)
                    try:
                        tu = self.twitter_api.tinyfy_url(t)
                    except:
                        note(u"Impossible to convert links. Try again", "error")
                        self.unlock_ui()
                        self.socket.stop()
                        return False
                    msg.replace(t,tu)

            # gps location
            gsm_latitude=0
            gsm_longitude=0
            pos_lat=0
            pos_long=0
            try:
               gsm_latitude, gsm_longitude = self.doLookup()
            except Exception, e:
               note(u"doLookup %s %s %s" %(e ,self.cellId, self.lac),"error")   
            if(self.gps_enabled):
               pos_lat = gps_data['position']['latitude']
               pos_long = gps_data['position']['longitude']
            if(pos_lat==0 and gsm_latitude!=0 and self.gps_enabled):
               pos_lat=gsm_latitude
               pos_long=gsm_longitude
               appuifw.note(u'No GPS signal','info')
            elif(self.gps_enabled==False and gsm_latitude!=0):
               pos_lat=gsm_latitude
               pos_long=gsm_longitude
            elif(pos_lat==0 and gsm_latitude==0):
               appuifw.note(u'No signal from GSM and GPS. Impossible to tweet.','error')
               self.unlock_ui()
               self.refresh_pages()
               self.socket.stop()
               return False
            params = urllib.urlencode({'t': msg, 'lat': pos_lat, 'lon': pos_long, 'u': self.twitter_user, 'p':self.twitter_password})
            headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
            conn = httplib.HTTPConnection("www.cagnulein.com:80")
            conn.request("POST", "/googlemaps_localizer/index.php", params, headers)
            
            try:
               self.refresh_timer.cancel()
            except:
               print u"timer not initalized"        

            self.no_notification=True
            self.refresh_timer.after(5, self.refresh_pages)
            self.socket.stop()            

            # second, divide message in several 140 char parts
            #msgs = self._splitmsg(msg)
            # post it part, waiting 2s between each part
            #nm = len(msgs)
            #i = 1
            #for m in msgs:
            #    self.set_title(u"UPD: %d/%d" % (i,nm))
            #    try:
            #        self.twitter_api.update(m,self.dlg.irto)
            #    except:
            #        note(u"Impossible to send messages. Try again", "error")
            #        self.unlock_ui()
            #        return False                    
            #    time.sleep(3)
            #    i += 1
        self.unlock_ui()
        return True
        
    def send_update(self):
        if self.gps_enabled==True and self.gps_on==False:
            self.gps_init()
        twu = self.twt_users.values()
        self.dlg = Notepad(self.send_update_cbk, self.update_msg, self.twitter_user, self.twitter_password, twu)
        self.dlg.run()
        
    def send_tweet_to_tweeter(self): pass
    def reply(self):
        idx = self.body.current()
        irto = self.timeline[self.page][idx][u'user'][u'screen_name']
        self.update_msg="@" + irto + " "
        self.send_update()
        self.update_msg=u""

    def retweet(self):
        idx = self.body.current()
        irto = self.timeline[self.page][idx][u'user'][u'screen_name']
        text = self.timeline[self.page][idx][u'text']
        self.update_msg="RT @" + irto + " " + text
        self.send_update()
        self.update_msg=u""
        
    def follow_links(self):
        idx = self.body.current()
        msg = self.timeline[self.page][idx][u'text']
        http = re.compile(u"http://\S+", re.IGNORECASE)
        links = re.findall(http, msg)
        if len(links) == 1:
            link = links[0]
        else:
            op = popup_menu(links,u"Which link?")
            if op is not None:
                link = links[op]
            else:
                return
        # prepare html file
        name = "html_" + time.strftime("%Y%m%d_%H%M%S", time.localtime()) + ".html"
        name = os.path.join(DEFDIR, "cache", name)
        try:
            fp = open(name,"wt")
            fp.write('<html>\n')
            fp.write('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>\n')
            fp.write('<head><title>Redirecting...</title></head>\n')
            fp.write('<body><script>document.location="%s"</script></body>' % link)
            fp.write('</html>')
            fp.close()
        except:
            note(u"Impossible to create html file","error")
            return
        viewer = Content_handler(self.refresh)
        try:
            viewer.open(name)
        except:
            note(u"Impossible to launch browser","error")
        self.socket.stop()
        
    def delete(self):
        idx = self.body.current()
        updt_id = self.timeline[self.page][idx][u'id']
        self.lock_ui(u"Deleting ...")
        try:
            self.twitter_api.destroy(updt_id)
        except:
            note(u"Impossible to delete update. Try again", "error")
        self.unlock_ui()
        del self.timeline[self.page][idx]
        del self.headlines[idx]
        self.refresh()
        self.socket.stop()
        
    def settings(self):
        def cbk():
            self.check_conn_params()
            self.refresh_pages()
            return True              
        self.dlg = Settings(cbk)
        self.dlg.run()

    def close_app(self):
        ny = popup_menu( [u"Yes", u"No"], u"Exit ?" )
        if ny is not None:
            if ny == 0:
                self.clear_cache()
                Application.close_app(self)

    def refresh(self):
        Application.refresh(self)
        idx = self.body.current()
        if not self.headlines:
            self.headlines = []
            self.avatars = []
        self.last_idx = min( self.last_idx, len(self.headlines)-1 )
        app.body.set_list(self.headlines,self.avatars)#, self.last_idx)
        self.set_title(u"Page %d" % (self.page))

    def clear_cache(self):
        not_all = False
        cache = os.path.join(DEFDIR, "cache")
        entries = os.listdir( cache )
        for e in entries:
            fname = os.path.join(cache,e)
            if os.path.isfile( fname ):
                try:
                    os.remove( fname )
                except:
                    not_all = True
        if not_all:
            note(u"Not all files in %s could be removed. Try to remove them later." % cache,"error")

    def about(self):
        def cbk():
            self.refresh()
            return True        
        self.dlg = About(cbk)
        self.dlg.run()

    def gps_init(self):
       if self.gps_on==True:
           return 
        
       #This function will start the updating of global variable (dictionary) 'gps_data' every 0.2 sec.
       #0.2 sec comes form 'interval = 20000000' set according to your needs
       #This function uses callback funtion gps
       global gps_data
       #First this fills the gps_data with 0.0 so that there is something before the first gps update
       gps_data = {'satellites': {'horizontal_dop': 0.0, 'used_satellites': 0, 'vertical_dop': 0.0, 'time': 0.0,'satellites': 0, 'time_dop':0.0}, 'position': {'latitude': 0.0, 'altitude': 0.0, 'vertical_accuracy': 0.0, 'longitude': 0.0, 'horizontal_accuracy': 0.0}, 'course': {'speed': 0.0, 'heading': 0.0, 'heading_accuracy': 0.0, 'speed_accuracy': 0.0}}
       try:
          positioning.select_module(positioning.default_module())
          positioning.set_requestors([{"type":"service","format":"application","data":"gps_app"}])
          positioning.position(course=1,satellites=1,callback=self.gps, interval=200000,partial=0)
          e32.ao_sleep(3)
       except Exception, e:
          note(u"Problem with GPS...","error")
          note(u"%s" % e,"error")
          
       self.gps_on=True
       
       try:
           self.gps_timer.cancel()
       except:
           print u"gps timer already stopped"
           
       try:    
          self.gps_timer.after(1800, self.gps_stop)
       except Exception, e:
          note(u"Problem starting GPS timeout...","error")
          note(u"%s" % e,"error")           
 
    def gps(self,event):
       global gps_data
       gps_data = event
 
    def gps_stop(self):
       if self.gps_on==False:
           return        
        
       #This function stops GPS
       try:
          if self.gps_enabled==True:
             positioning.stop_position()
             self.gps_on=False
       except Exception, e:
          appuifw.note(u'Error during shutting down GPS','error')
          note(u"%s" % e,"error")

    def doLookup(self, host = "www.google.com", port = 80):
      page = "/glm/mmap"
      http = HTTP(host, port)
      result = None
      errorCode = 0
      content_type = 'application/binary'
      body = pack('>hqh2sh13sh5sh3sBiiihiiiiii', 21, 0, 2, 'in', 13, "Nokia N95 8Gb", 5,"1.3.1", 3, "Web", 27, 0, 0, 3, 0, self.cellId, self.lac, 0, 0, 0, 0)   
      http.putrequest('POST', page)
      http.putheader('Content-Type', content_type)
      http.putheader('Content-Length', str(len(body)))
      http.endheaders()
      http.send(body)
      errcode, errmsg, headers = http.getreply()
      result = http.file.read()
      # could need some modification to get the answer: here I just need
      # to get the 5 first characters
      if (errcode == 200):
        (a, b,errorCode, latitude, longitude, c, d, e) = unpack(">hBiiiiih",result)
        latitude = latitude / 1000000.0
        longitude = longitude / 1000000.0
      return latitude, longitude
        
if __name__ == "__main__":

    imd = Iamdoing()
    imd.run()
